package com.gitee.deeround.jdbchelper.core.impl;

import com.gitee.deeround.jdbchelper.core.DbActionQuery;
import com.gitee.deeround.jdbchelper.core.Dialect;
import com.gitee.deeround.jdbchelper.core.DialectHelper;
import com.gitee.deeround.jdbchelper.out.DataTable;
import com.gitee.deeround.jdbchelper.out.PageList;
import com.gitee.deeround.jdbchelper.resultSetExtractors.*;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class DbActionQueryImpl extends BaseDbAction implements DbActionQuery {

    private final JdbcTemplate jdbcTemplate;

    public DbActionQueryImpl(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }


    //================queryForDataTable===================

    @Override
    public DataTable queryForDataTable(String sql) {
        return queryForDataTable(sql, null);
    }

    @Override
    public DataTable queryForDataTable(String sql, Object[] args) {
        if (args != null && args.length > 0) {
            return queryForObject(sql, args, new DataTableResultSetExtractor("dt"));
        } else {
            return queryForObject(sql, new DataTableResultSetExtractor("dt"));
        }
    }


    //================queryForList===================

    @Override
    public List<Map<String, Object>> queryForList(String sql) {
        return queryForList(sql, null);
    }

    @Override
    public List<Map<String, Object>> queryForList(String sql, Object[] args) {
        if (args != null && args.length > 0) {
            return queryForObject(sql, args, new MapResultSetExtractor());
        } else {
            return queryForObject(sql, new MapResultSetExtractor());
        }
    }

    @Override
    public <T> List<T> queryForListObject(String sql, Class<T> elementType) {
        return queryForListObject(sql, null, elementType);
    }

    @Override
    public <T> List<T> queryForListObject(String sql, Object[] args, Class<T> elementType) {
        if (args != null && args.length > 0) {
            return jdbcTemplate.query(sql, new ListObjectResultSetExtractor<T>(elementType), args);
        } else {
            return jdbcTemplate.query(sql, new ListObjectResultSetExtractor<T>(elementType));
        }
    }

    @Override
    public <T> List<T> queryForListObject(String sql, CustomApply<T> customApply) {
        return queryForListObject(sql, null, customApply);
    }

    @Override
    public <T> List<T> queryForListObject(String sql, Object[] args, CustomApply<T> customApply) {
        if (args != null && args.length > 0) {
            return jdbcTemplate.query(sql, new CustomListObjectResultSetExtractor<>(customApply), args);
        } else {
            return jdbcTemplate.query(sql, new CustomListObjectResultSetExtractor<>(customApply));
        }
    }


    //================queryForObject（只取第一行数据）===================


    @Override
    public Map queryForMap(String sql) {
        List<Map<String, Object>> list = queryForList(sql);
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public Map queryForMap(String sql, Object[] args) {
        List<Map<String, Object>> list = queryForList(sql, args);
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public <T> T queryForObject(String sql, Class<T> elementType) {
        List<T> list = queryForListObject(sql, elementType);
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public <T> T queryForObject(String sql, Object[] args, Class<T> elementType) {
        List<T> list = queryForListObject(sql, args, elementType);
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public <T> T queryForObject(String sql, CustomApply<T> customApply) {
        List<T> list = queryForListObject(sql, customApply);
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public <T> T queryForObject(String sql, Object[] args, CustomApply<T> customApply) {
        List<T> list = queryForListObject(sql, args, customApply);
        return list.isEmpty() ? null : list.get(0);
    }


    //================queryForValue(只取第一行第一列的值，无数据为null)===================


    @Override
    public Object queryForValue(String sql) {
        DataTable dt = queryForDataTable(sql);
        if (dt != null && dt.getRows().size() > 0) {
            Object[] row = dt.getRows().get(0);
            if (row != null && row.length > 0) {
                return row[0];
            }
        }
        return null;
    }

    @Override
    public Object queryForValue(String sql, Object[] args) {
        DataTable dt = queryForDataTable(sql, args);
        if (dt != null && dt.getRows().size() > 0) {
            Object[] row = dt.getRows().get(0);
            if (row != null && row.length > 0) {
                return row[0];
            }
        }
        return null;
    }

    @Override
    public String queryForString(String sql) {
        Object value = queryForValue(sql);
        return value == null ? null : value.toString();
    }

    @Override
    public String queryForString(String sql, Object[] args) {
        Object value = queryForValue(sql, args);
        return value == null ? null : value.toString();
    }

    @Override
    public Integer queryForInteger(String sql) {
        Object value = queryForValue(sql);
        return value == null ? null : Integer.parseInt(value.toString());
    }

    @Override
    public Integer queryForInteger(String sql, Object[] args) {
        Object value = queryForValue(sql, args);
        return value == null ? null : Integer.parseInt(value.toString());
    }

    @Override
    public BigDecimal queryForDecimal(String sql) {
        Object value = queryForValue(sql);
        return value == null ? null : new BigDecimal(value.toString());
    }

    @Override
    public BigDecimal queryForDecimal(String sql, Object[] args) {
        Object value = queryForValue(sql, args);
        return value == null ? null : new BigDecimal(value.toString());
    }


    private <T> T queryForObject(String sql, ResultSetExtractor<T> resultSetExtractor) {
        return queryForObject(sql, null, resultSetExtractor);
    }

    private <T> T queryForObject(String sql, Object[] args, ResultSetExtractor<T> resultSetExtractor) {
        if (args != null && args.length > 0) {
            return jdbcTemplate.query(sql, resultSetExtractor, args);
        } else {
            return jdbcTemplate.query(sql, resultSetExtractor);
        }
    }


    //================queryForPage===================

    @Override
    public PageList<Map<String, Object>> queryForPage(String sql, int pageNum, int pageSize) {
        return queryForPage(sql, null, pageNum, pageSize);
    }

    @Override
    public PageList<Map<String, Object>> queryForPage(String sql, Object[] args, int pageNum, int pageSize) {
        Dialect dialect = DialectHelper.getDialect(jdbcTemplate);
        String countSql = dialect.getCountSql(sql);
        String pageSql = dialect.getPageSql(sql, pageNum, pageSize);

        Integer total = queryForInteger(countSql, args);
        List<Map<String, Object>> list = total <= (pageNum - 1) * pageSize ? new ArrayList<>() : queryForList(pageSql, args);
        return new PageList<>(list, pageNum, pageSize, total);
    }

    @Override
    public <T> PageList<T> queryForPage(String sql, int pageNum, int pageSize, Class<T> elementType) {
        return queryForPage(sql, null, pageNum, pageSize, elementType);
    }

    @Override
    public <T> PageList<T> queryForPage(String sql, Object[] args, int pageNum, int pageSize, Class<T> elementType) {
        Dialect dialect = DialectHelper.getDialect(jdbcTemplate);
        String countSql = dialect.getCountSql(sql);
        String pageSql = dialect.getPageSql(sql, pageNum, pageSize);

        Integer total = queryForInteger(countSql, args);
        List<T> list = total <= (pageNum - 1) * pageSize ? new ArrayList<>() : queryForListObject(pageSql, args, elementType);
        return new PageList<>(list, pageNum, pageSize, total);
    }

    @Override
    public <T> PageList<T> queryForPage(String sql, int pageNum, int pageSize, CustomApply<T> customApply) {
        return null;
    }

    @Override
    public <T> PageList<T> queryForPage(String sql, Object[] args, int pageNum, int pageSize, CustomApply<T> customApply) {
        Dialect dialect = DialectHelper.getDialect(jdbcTemplate);
        String countSql = dialect.getCountSql(sql);
        String pageSql = dialect.getPageSql(sql, pageNum, pageSize);

        Integer total = queryForInteger(countSql, args);
        List<T> list = total <= (pageNum - 1) * pageSize ? new ArrayList<>() : queryForListObject(pageSql, args, customApply);
        return new PageList<>(list, pageNum, pageSize, total);
    }

    @Override
    public String getPageSql(String sql, int pageNum, int pageSize) {
        Dialect dialect = DialectHelper.getDialect(jdbcTemplate);
        return dialect.getPageSql(sql, pageNum, pageSize);
    }


}
